import { PrismaClient } from '@prisma/client';
import {
  Dictionary,
  DictionaryItem,
  CreateDictionaryRequest,
  UpdateDictionaryRequest,
  CreateDictionaryItemRequest,
  UpdateDictionaryItemRequest,
  DictionaryQueryParams,
  DictionaryItemQueryParams,
} from '../models/Dictionary';
import { generateTimestampNumericUUID } from '../utils/uuid';

const prisma = new PrismaClient();

export class DictionaryService {
  // 字典管理
  async createDictionary(data: CreateDictionaryRequest): Promise<Dictionary> {
    const dictionary = await prisma.dictionary.create({
      data: {
        id: generateTimestampNumericUUID(),
        ...data,
      },
    });
    return {
      ...dictionary,
      description: dictionary.description ?? undefined,
      status: dictionary.status ?? undefined,
      sort: dictionary.sort ?? undefined,
      createdAt: dictionary.createdAt ?? undefined,
      updatedAt: dictionary.updatedAt ?? undefined,
    };
  }

  async updateDictionary(
    id: string,
    data: UpdateDictionaryRequest
  ): Promise<Dictionary> {
    const dictionary = await prisma.dictionary.update({
      where: { id },
      data,
    });
    return {
      ...dictionary,
      description: dictionary.description ?? undefined,
      status: dictionary.status ?? undefined,
      sort: dictionary.sort ?? undefined,
      createdAt: dictionary.createdAt ?? undefined,
      updatedAt: dictionary.updatedAt ?? undefined,
    };
  }

  async deleteDictionary(id: string): Promise<void> {
    // 先删除相关的字典项
    await prisma.dictionaryItem.deleteMany({
      where: { dictionaryId: id },
    });
    // 再删除字典
    await prisma.dictionary.delete({
      where: { id },
    });
  }

  async getDictionaryById(id: string): Promise<Dictionary | null> {
    const dictionary = await prisma.dictionary.findUnique({
      where: { id },
      include: {
        items: {
          where: { status: 1 },
          orderBy: [{ sort: 'asc' }, { createdAt: 'asc' }],
        },
      },
    });
    if (!dictionary) return null;
    return {
      ...dictionary,
      description: dictionary.description ?? undefined,
      status: dictionary.status ?? undefined,
      sort: dictionary.sort ?? undefined,
      createdAt: dictionary.createdAt ?? undefined,
      updatedAt: dictionary.updatedAt ?? undefined,
    };
  }

  async getDictionaryByCode(code: string): Promise<Dictionary | null> {
    const dictionary = await prisma.dictionary.findUnique({
      where: { code },
      include: {
        items: {
          where: { status: 1 },
          orderBy: [{ sort: 'asc' }, { createdAt: 'asc' }],
        },
      },
    });
    if (!dictionary) return null;
    return {
      ...dictionary,
      description: dictionary.description ?? undefined,
      status: dictionary.status ?? undefined,
      sort: dictionary.sort ?? undefined,
      createdAt: dictionary.createdAt ?? undefined,
      updatedAt: dictionary.updatedAt ?? undefined,
    };
  }

  async getDictionaries(params: DictionaryQueryParams) {
    const { page = 1, pageSize = 10, code, name, status } = params;
    const skip = (page - 1) * pageSize;

    const where: any = {};
    if (code) where.code = { contains: code };
    if (name) where.name = { contains: name };
    if (status !== undefined) where.status = status;

    const [dictionaries, total] = await Promise.all([
      prisma.dictionary.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: [{ sort: 'asc' }, { createdAt: 'desc' }],
        include: {
          _count: {
            select: { items: true },
          },
        },
      }),
      prisma.dictionary.count({ where }),
    ]);

    return {
      data: dictionaries.map(dict => ({
        ...dict,
        description: dict.description ?? undefined,
        status: dict.status ?? undefined,
        sort: dict.sort ?? undefined,
        createdAt: dict.createdAt ?? undefined,
        updatedAt: dict.updatedAt ?? undefined,
      })),
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  // 字典项管理
  async createDictionaryItem(
    data: CreateDictionaryItemRequest
  ): Promise<DictionaryItem> {
    const item = await prisma.dictionaryItem.create({
      data: {
        id: generateTimestampNumericUUID(),
        ...data,
      },
    });
    return {
      ...item,
      status: item.status ?? undefined,
      sort: item.sort ?? undefined,
      parentId: item.parentId ?? undefined,
      createdAt: item.createdAt ?? undefined,
      updatedAt: item.updatedAt ?? undefined,
    };
  }

  async updateDictionaryItem(
    id: string,
    data: UpdateDictionaryItemRequest
  ): Promise<DictionaryItem> {
    const item = await prisma.dictionaryItem.update({
      where: { id },
      data,
    });
    return {
      ...item,
      status: item.status ?? undefined,
      sort: item.sort ?? undefined,
      parentId: item.parentId ?? undefined,
      createdAt: item.createdAt ?? undefined,
      updatedAt: item.updatedAt ?? undefined,
    };
  }

  async deleteDictionaryItem(id: string): Promise<void> {
    // 先删除子项
    await prisma.dictionaryItem.deleteMany({
      where: { parentId: id },
    });
    // 再删除自己
    await prisma.dictionaryItem.delete({
      where: { id },
    });
  }

  async getDictionaryItemById(id: string): Promise<DictionaryItem | null> {
    const item = await prisma.dictionaryItem.findUnique({
      where: { id },
      include: {
        dictionary: true,
        parent: true,
        children: {
          where: { status: 1 },
          orderBy: [{ sort: 'asc' }, { createdAt: 'asc' }],
        },
      },
    });
    if (!item) return null;
    return {
      ...item,
      status: item.status ?? undefined,
      sort: item.sort ?? undefined,
      parentId: item.parentId ?? undefined,
      createdAt: item.createdAt ?? undefined,
      updatedAt: item.updatedAt ?? undefined,
    };
  }

  async getDictionaryItems(params: DictionaryItemQueryParams) {
    const {
      page = 1,
      pageSize = 10,
      dictionaryId,
      label,
      status,
      parentId,
    } = params;
    const skip = (page - 1) * pageSize;

    const where: any = {};
    if (dictionaryId) where.dictionaryId = dictionaryId;
    if (label) where.label = { contains: label };
    if (status !== undefined) where.status = status;
    if (parentId !== undefined) where.parentId = parentId;

    const [items, total] = await Promise.all([
      prisma.dictionaryItem.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: [{ sort: 'asc' }, { createdAt: 'desc' }],
        include: {
          dictionary: {
            select: { id: true, name: true },
          },
          parent: {
            select: { id: true, label: true },
          },
        },
      }),
      prisma.dictionaryItem.count({ where }),
    ]);

    return {
      data: items.map(item => ({
        ...item,
        status: item.status ?? undefined,
        sort: item.sort ?? undefined,
        parentId: item.parentId ?? undefined,
        createdAt: item.createdAt ?? undefined,
        updatedAt: item.updatedAt ?? undefined,
      })),
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  async getDictionaryItemsByDictionaryCode(
    dictionaryCode: string
  ): Promise<DictionaryItem[]> {
    const items = await prisma.dictionaryItem.findMany({
      where: {
        dictionary: { code: dictionaryCode },
        status: 1,
      },
      orderBy: [{ sort: 'asc' }, { createdAt: 'asc' }],
    });
    return items.map(item => ({
      ...item,
      status: item.status ?? undefined,
      sort: item.sort ?? undefined,
      parentId: item.parentId ?? undefined,
      createdAt: item.createdAt ?? undefined,
      updatedAt: item.updatedAt ?? undefined,
    }));
  }

  // 批量操作
  async batchUpdateDictionaryItemsSort(
    items: { id: string; sort: number }[]
  ): Promise<void> {
    await prisma.$transaction(
      items.map(item =>
        prisma.dictionaryItem.update({
          where: { id: item.id },
          data: { sort: item.sort },
        })
      )
    );
  }

  async batchUpdateDictionariesSort(
    dictionaries: { id: string; sort: number }[]
  ): Promise<void> {
    await prisma.$transaction(
      dictionaries.map(dict =>
        prisma.dictionary.update({
          where: { id: dict.id },
          data: { sort: dict.sort },
        })
      )
    );
  }
}

export const dictionaryService = new DictionaryService();
